In software programming, a compiler is a computer program (or set of programs) that translates text written in a computer language (the source language) into another computer language (the target language). The original text language is usually called the source code and the output language is usually called object code. Commonly the output has a form suitable for processing by other programs (e.g., a linker), but it may be a human-readable text file. The Common Object File Format (COFF) and Executable and Linking Format (ELF) are examples of file formats for executables, object code, and shared libraries. A linker or link editor is a program that further processes the object code files and libraries generated by compilers and processes them into executable code. Some architectures will introduce additional steps of processing between compilation and linking for various purposes such as source-language-specific binding, auxiliary code generation, and automated instantiation refactoring. This chain of processing tools is sometimes called the program-build-tool-chain.
Executable code generated through compilation and linking is used to realize functionality of large and small products in a wide variety of applications. It is always desirable to produce smaller executable programs without reducing the correctness, performance, or functionality of the resulting program.
Embedded systems usually involve computers with less computing and memory resources. Typically embedded systems are reduced to the smallest computing resources feasible to support the target application to optimize the economic cost of each deployed system. Thus on embedded systems the size of the resulting executable code is even more critical. Each reduction in object code size may have direct financial benefit.
One area of emerging interest in embedded systems is Software Defined Radios (SDRs). A standard for building SDRs is the Software Communications Architecture (SCA), an open architecture framework promulgated by the U.S. militaries Joint Tactical Radio System (JTRS) program that governs the structure and operation of the radio, enabling it to dynamically load and run waveforms and be networked into an integrated system. The SCA specifies a foundation built upon CORBA (Common Object Request Broker Architecture) distributed communications services, such as ORBexpress® provided by Objective Interface Systems, and a Portable Operating System Interface (POSIX) compliant real-time operating system. The functions provided by the SCA results in a sophisticated software platform that may occupy significant computing resources on the radio, placing a strain on size, weight, and power (SWaP).
Software developers have been challenged to meet the stringent resource and performance requirements often associated with SDRs, including the footprint of executable code generated from compilation of developed source code. Known approaches for reducing software footprint include the use of a subset of CORBA standard and the Software Communications Architecture (SCA) standard. This approach, however, results in removal of functionality for achieving performance objectives. Developers must speculate which functionality to remove, which could result in inadequate functionality or imposing artificial restraints for many radios or waveforms. Moreover, by deviating from the standards, conformance tests, such as JTRS Technology Laboratory (JTeL) JTRS Test Application (JTAP), are likely to fail.
A method for reducing the size of executable code eliminates “dead code,” namely, code that will not or could not ever be called or executed given a specific set of application code. Dead code, for example, is code that is not executed during any execution of the program, or code whose execution cannot affect the program's observable behavior. Another term sometimes used for dead code is “unreachable code”.
Object-oriented programming (OOP) is a programming paradigm that uses “classes” and the instantiations of those classes called “objects” to facilitate the design and implementation of applications and computer programs. OOP utilizes several techniques, including inheritance, modularity, polymorphism, and encapsulation. Ada, C#, C++, Java, Objective C, and Smalltalk are examples of OOP languages. OOP languages have varying degrees of support for concepts such as the creation and calling of classes, class members, inheritance, multiple inheritance, virtual inheritance, virtual functions, and run-time dispatching to virtual functions. Run-time dispatching to virtual functions is frequently realized with mechanisms such as dictionaries, dispatch tables or vtables. Such languages also allows for creation of libraries that can be reused in many different applications. However, any given executable for a program will typically only use a portion of the code in that program and a portion of the code available in these libraries.
Several techniques are common in program-build-tool-chains to reduce the size of the executable program:
According to one technique, archive libraries containing multiple files of object code called modules are scanned by the linker and the linker only pulls in the modules necessary to resolve an external reference caused by a program's source code.                Problem (A): Unfortunately this technique pulls in all functions, methods, and variables within a module even if only one of the functions, methods, or variables in that module is referenced. This unfortunate effect cascades because all of the symbols referenced in the unneeded functions, methods, and variables will need further resolution and cause even more unneeded code from other modules and libraries to get pulled into to the executable application.        Problem (B): This technique is less useful for virtual functions in OOP languages. The compiler will always generate a dispatch table for every class that references the implementation of all of the virtual functions in that class. The result is that any reference to any function, method, or variable in a class in a module in a library will cause all of the virtual functions for a class to get pulled into the executable program even if these virtual functions cannot and thus will not ever be called.        
One less common optimization of (1) is for the compiler to put each function, method, and variable in a separate module. This greatly reduces problem (1.A). This optimization does not help alleviate problem (1.B).
Other prior art has addressed the problem of eliminating unused functions; an example of such prior art is, e.g., A. Srivastava, “Unused procedures in object-oriented programming”, ACM Letters on Programming Languages and Systems, 1(4), pp. 355-364. Other prior art has focused on eliminating dead code at the statement level; see e.g., A. Aho, R. Sethi, and J. D. Ullman, “Compilers, Principles, Techniques, and Tools”, Addison-Wesley, 1986, and F. Tip, “A Survey of Program Slicing Techniques”, Journal of Programming Languages 3, 3, (1995), pp. 121-189.
Still other prior art has addressed the elimination of data members and subobjects that are not accessed during any execution of an application; see Tip et al., “Slicing Class Hierarchies in C++”, Proceedings of the Eleventh Annual Conference on Object-Oriented Programming, Languages, and Applications (OOPSLA'96), (San Jose, Calif., October 1996), ACM SIGPLAN Notices 31(10), pp. 179-197. Elimination of code related to class hierarchies that unnecessarily exhibit virtual inheritance is also know.
U.S. Pat. No. 5,983,020 discloses a rule-based engine for transformation of class hierarchy of an object-oriented program. The engine transforms a class hierarchy of an object-oriented program to a new class hierarchy based upon a set of rules. The new class hierarchy is a simplification of the inheritance structure that reduces the number of compiler-generated fields in objects.
U.S. Pat. No. 5,481,708 discloses a system and method for optimizing object-oriented compilations. The disclosed object-oriented development system includes a language compiler having an optimizer for generating computer applications with improved speed and size. C++ optimization methods include virtual function and base optimization, using thunks for virtual member pointers, and passing classes by value.
With the continuing requirement for reducing the size of executable code, particularly in applications where code footprint is at a premium, there still exists a need for a method or system that further reduces the size of generated executable code without compromising functionality or departing from standards.